package org.mineground.player;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.mineground.Main;
import org.mineground.Utilities;
import org.mineground.handlers.NameBanHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * 
 * @file MinegroundPlayer.java (22.01.2012)
 * @author Daniel Koenen
 *
 */
public class MinegroundPlayer {
    private static final Logger ExceptionLogger = LoggerFactory.getLogger(MinegroundPlayer.class);
    
    public static final int INVALID_PROFILE_ID = -1;
    public static final int MUTED_TIME = 0;
    public static final int MUTED_PERMANENT = 1;
    public static final int MUTED_NOTMUTED = 2;
    
    private Player player;
    private Player pmReply;
    
    private short invalidLoginAttempts;
    
    private int profileId;
    private int profileState;
    private int onlineSeconds;
    private int kills;
    private int deaths;
    private int placedBlocks;
    private int removedBlocks;
    private int wonReactiontests;
    private int groupChatId;
    private int homeId;
    private int muteTime;
    
    private boolean isLoggedIn;
    private boolean godToggle;
    private boolean teleportToggle;
    private boolean pvpToggle;
    private boolean isKicked;
    
    private Date registerDate;
    private World dieWorld;
    private ItemStack[] backupInventory;
    
    private long muteTick;
    private long joinTick;
    private long networkAddress;

    public MinegroundPlayer(Player player) {
        this.player = player;
        this.profileId = INVALID_PROFILE_ID;
        this.homeId = -1;
    }

    public void initializePlayer() {
        PreparedStatement queryStatement = null;
        ResultSet queryResult = null;
        
        try {
            queryStatement = Main.getInstance().getDatabaseHandler().getConnection().prepareStatement("SELECT player_id, state FROM lvm_players WHERE login_name = ? LIMIT 1");
            queryStatement.setString(1, player.getName());
            queryStatement.execute();
            queryResult = queryStatement.getResultSet();

            if (queryResult.next()) {
                profileId = queryResult.getInt(1);
                profileState = queryResult.getInt(2);
                
                if (profileState == 0) {
                    NameBanHandler.kickPlayer(player.getName(), "Server", "Please activate your account first");
                }
            }
        } 
        
        catch (Exception exception) {
            ExceptionLogger.error("Exception caught", exception);
        }
        
        finally {
            try {
                if (queryStatement != null) {
                    queryStatement.close();
                }

                if (queryResult != null) {
                    queryResult.close();
                }
            }
            
            catch (Exception exception) {
                ExceptionLogger.error("Exception caught", exception);
            }
        }
    }

    public void loadPlayer() {
        if (!isRegistered()) {
            return;
        }

        StringBuilder queryCommand = new StringBuilder();
        queryCommand.append("SELECT ");
        queryCommand.append("s.has_god, ");
        queryCommand.append("s.allow_tp, ");
        queryCommand.append("s.group_chat_id, ");
        queryCommand.append("s.home_id, ");
        queryCommand.append("p.registered, ");
        queryCommand.append("UNIX_TIMESTAMP(p.last_online), ");
        queryCommand.append("p.ip_address, ");
        queryCommand.append("t.kills, ");
        queryCommand.append("t.deaths, ");
        queryCommand.append("t.online_time, ");
        queryCommand.append("t.reactiontests, ");
        queryCommand.append("t.blocks_placed, ");
        queryCommand.append("t.blocks_removed ");
        queryCommand.append("FROM lvm_players p ");
        queryCommand.append("LEFT JOIN lvm_player_settings s ON p.player_id = s.player_id ");
        queryCommand.append("LEFT JOIN lvm_player_statistics t ON p.player_id = t.player_id ");
        queryCommand.append("WHERE p.player_id = ?");
        
        PreparedStatement queryStatement = null;
        ResultSet queryResult = null;

        try {
            queryStatement = Main.getInstance().getDatabaseHandler().getConnection().prepareStatement(queryCommand.toString());
            queryStatement.setInt(1, getProfileId());
            queryStatement.execute();
            queryResult = queryStatement.getResultSet();

            if (queryResult.next()) {
                setGodToggle(queryResult.getBoolean(1));
                setTeleportToggle(queryResult.getBoolean(2));
                setGroupChatId(queryResult.getInt(3));
                setHomeId(queryResult.getInt(4));

                registerDate = queryResult.getDate(5);
                long loginDate = queryResult.getLong(6);
                
                networkAddress = queryResult.getLong(7);

                kills = queryResult.getInt(8);
                deaths = queryResult.getInt(9);
                onlineSeconds = queryResult.getInt(10);
                wonReactiontests = queryResult.getInt(11);
                placedBlocks = queryResult.getInt(12);
                removedBlocks = queryResult.getInt(13);

                if (groupChatId != -1 && Main.getInstance().getGroupChatHandler().doesGroupExist(groupChatId)) {
                    Main.getInstance().getGroupChatHandler().getGroupChat(queryResult.getInt(3)).addPlayer(player);
                }

                long playerAddress = Utilities.ipToLong(player.getAddress().getAddress().getHostAddress());
                
                Calendar oldDay = Calendar.getInstance();
                oldDay.setTime(new Date(loginDate * 1000));
                
                int lastLoginDay = oldDay.get(Calendar.DAY_OF_YEAR);
                int yearDay = Calendar.getInstance().get(Calendar.DAY_OF_YEAR);
                
                if (lastLoginDay == yearDay && networkAddress == playerAddress) { 
                    player.sendMessage(ChatColor.GREEN + "You have been automatically logged in.");
                    logIn();
                }
            }
        } 
        
        catch (Exception exception) {
            ExceptionLogger.error("Exception caught", exception);
        }
        
        finally {
            try {
                if (queryStatement != null) {
                    queryStatement.close();
                }

                if (queryResult != null) {
                    queryResult.close();
                }
            }
            
            catch (Exception exception) {
                ExceptionLogger.error("Exception caught", exception);
            }
        }
    }

    public void savePlayer() {
        if (!isRegistered()) {
            return;
        }

        StringBuilder queryCommand = new StringBuilder();
        queryCommand.append("UPDATE lvm_players p ");
        queryCommand.append("LEFT JOIN lvm_player_settings s ON p.player_id = s.player_id ");
        queryCommand.append("LEFT JOIN lvm_player_statistics t ON p.player_id = t.player_id SET ");
        queryCommand.append("p.ip_address = ?, ");
        queryCommand.append("s.has_god = ?, ");
        queryCommand.append("s.allow_tp = ?, ");
        queryCommand.append("s.group_chat_id = ?, ");
        queryCommand.append("s.home_id = ?, ");
        queryCommand.append("p.last_online = NOW(), ");
        queryCommand.append("t.kills = ?, ");
        queryCommand.append("t.deaths = ?, ");
        queryCommand.append("t.online_time = ?, ");
        queryCommand.append("t.reactiontests = ?, ");
        queryCommand.append("t.blocks_placed = ?, ");
        queryCommand.append("t.blocks_removed = ? ");
        queryCommand.append("WHERE p.player_id = ?");
        
        PreparedStatement queryStatement = null;

        try {
            queryStatement = Main.getInstance().getDatabaseHandler().getConnection().prepareStatement(queryCommand.toString());

            queryStatement.setLong(1, Utilities.ipToLong(player.getAddress().getAddress().getHostAddress()));
            queryStatement.setBoolean(2, getGodToggle());
            queryStatement.setBoolean(3, getTeleportToggle());
            queryStatement.setInt(4, getGroupChatId());
            queryStatement.setInt(5, getHomeId());
            queryStatement.setInt(6, getKills());
            queryStatement.setInt(7, getDeaths());
            queryStatement.setInt(9, getWonReactiontests());
            queryStatement.setInt(10, getPlacedBlocks());
            queryStatement.setInt(11, getRemovedBlocks());
            queryStatement.setInt(12, getProfileId());

            long onlineTime = (System.currentTimeMillis() - getJoinTick()) / 1000L;
            onlineTime += getOnlineSeconds();
            queryStatement.setLong(8, onlineTime);
            
            queryStatement.execute();
            queryStatement.close();
        } 
        
        catch (Exception exception) {
            ExceptionLogger.error("Exception caught", exception);
        }
        
        finally {
            try {
                if (queryStatement != null) {
                    queryStatement.close();
                }
            }
            
            catch (Exception exception) {
                ExceptionLogger.error("Exception caught", exception);
            }
        }
    }

    public int isMuted() {
        if (getMuteTime() == -1) {
            return MUTED_PERMANENT;
        } 
        
        else if (getMuteTime() > 0) {
            return MUTED_TIME;
        }

        return MUTED_NOTMUTED;
    }

    public boolean isRegistered() {
        return (getProfileId() == INVALID_PROFILE_ID) ? (false) : (true);
    }

    public void initializeSurvivalMovementDelay(Location teleportLocation) {
        Timer teleportTimer = new Timer();
        Location playerLocation = player.getLocation();

        teleportTimer.schedule(new SurvivalTeleport(player, playerLocation, teleportLocation), 3000);

        player.sendMessage(ChatColor.DARK_GREEN + "You'll be teleported in 3 seconds, please don't move.");
    }

    public void mutePlayer(int minutesToMute) {
        if (isMuted() < MUTED_NOTMUTED) {
            return;
        }

        setMuteTime(minutesToMute);
        setMuteTick(System.currentTimeMillis());
    }

    public void unmutePlayer() {
        if (isMuted() == MUTED_NOTMUTED) {
            return;
        }

        setMuteTime((int) 0);
        setMuteTick(0);
    }

    public void addInvalidLoginAttempt() {
        invalidLoginAttempts++;
    }

    public void addKill() {
        kills++;
    }

    public void addDeath() {
        deaths++;
    }

    public void addPlacedBlock() {
        placedBlocks++;
    }

    public void addRemovedBlock() {
        removedBlocks++;
    }

    public void addReactiontest() {
        wonReactiontests++;
    }

    public Player getPlayer() {
        return player;
    }

    public int getProfileId() {
        return profileId;
    }

    public int getOnlineSeconds() {
        return onlineSeconds;
    }

    public int getKills() {
        return kills;
    }

    public int getDeaths() {
        return deaths;
    }

    public int getPlacedBlocks() {
        return placedBlocks;
    }

    public int getRemovedBlocks() {
        return removedBlocks;
    }

    public int getWonReactiontests() {
        return wonReactiontests;
    }

    public boolean getGodToggle() {
        return godToggle;
    }

    public void setGodToggle(boolean godToggle) {
        this.godToggle = godToggle;
    }

    public boolean getTeleportToggle() {
        return teleportToggle;
    }

    public void setTeleportToggle(boolean teleportToggle) {
        this.teleportToggle = teleportToggle;
    }

    public Date getRegisterDate() {
        return registerDate;
    }

    public long getJoinTick() {
        return joinTick;
    }

    public Player getReplyPlayer() {
        return pmReply;
    }

    public void setReplyPlayer(Player pmReply) {
        this.pmReply = pmReply;
    }

    public int getGroupChatId() {
        return groupChatId;
    }

    public void setGroupChatId(int groupChatId) {
        this.groupChatId = groupChatId;
    }

    public boolean getPvPToggle() {
        return pvpToggle;
    }

    public void setPvPToggle(boolean pvpToggle) {
        this.pvpToggle = pvpToggle;
    }

    public int getHomeId() {
        return homeId;
    }

    public void setHomeId(int homeId) {
        this.homeId = homeId;
    }

    public World getDieWorld() {
        return dieWorld;
    }

    public void setDieWorld(World dieWorld) {
        this.dieWorld = dieWorld;
    }

    public long getMuteTick() {
        return muteTick;
    }

    public void setMuteTick(long muteTick) {
        this.muteTick = muteTick;
    }

    public int getMuteTime() {
        return muteTime;
    }

    public void setMuteTime(int muteTime) {
        this.muteTime = muteTime;
    }

    public ItemStack[] getBackupInventory() {
        return backupInventory;
    }

    public void setBackupInventory(ItemStack[] backupInventory) {
        this.backupInventory = backupInventory;
    }

    public long getNetworkAddress() {
        return networkAddress;
    }

    public boolean isLoggedIn() {
        return isLoggedIn;
    }

    public short getInvalidLoginAttempts() {
        return invalidLoginAttempts;
    }
    
    public void logIn() {
        isLoggedIn = true;
        joinTick = System.currentTimeMillis();
        
        try {
            if (profileState == 1) {
                Main.getInstance().getServer().dispatchCommand(Main.getInstance().getServer().getConsoleSender(), "pex user " + player.getName() + " delete");
                Main.getInstance().getServer().dispatchCommand(Main.getInstance().getServer().getConsoleSender(), "pex user " + player.getName() + " group set Builder");

                PreparedStatement queryStatement = Main.getInstance().getDatabaseHandler().getConnection().prepareStatement("UPDATE lvm_players SET state = 2 WHERE player_id = ?");
                queryStatement.setInt(1, profileId);
                queryStatement.execute();
                queryStatement.close();

                profileState = 2;
                Utilities.sendMessageToAll(ChatColor.AQUA + player.getName() + " has verified his/her registration and has been promoted to Builder!");
            }
        }
        
        catch (Exception exception) {
            ExceptionLogger.error("Exception caught", exception);
        }
    }

    public boolean isKicked() {
        return isKicked;
    }

    public void setKicked(boolean isKicked) {
        this.isKicked = isKicked;
    }
}

class SurvivalTeleport extends TimerTask {
    private Player playerToTeleport;
    private Location initializeLocation;
    private Location teleportLocation;

    public SurvivalTeleport(Player playerToTeleport, Location initializeLocation, Location teleportLocation) {
        this.playerToTeleport = playerToTeleport;
        this.initializeLocation = initializeLocation;
        this.teleportLocation = teleportLocation;
    }

    @Override
    public void run() {
        if (Main.getInstance().getServer().getPlayer(playerToTeleport.getName()) == null) {
            cancel();
            return;
        }

        Location oldLocation = new Location(initializeLocation.getWorld(), initializeLocation.getBlockX(),
                initializeLocation.getBlockY(), initializeLocation.getBlockZ());
        Location newLocation = new Location(initializeLocation.getWorld(), playerToTeleport.getLocation().getBlockX(),
                playerToTeleport.getLocation().getBlockY(), playerToTeleport.getLocation().getBlockZ());

        if (!oldLocation.equals(newLocation)) {
            playerToTeleport.sendMessage(ChatColor.RED
                    + "* Error: Please don't move while trying to teleport, try again.");
            cancel();
            return;
        }

        playerToTeleport.teleport(teleportLocation);
        playerToTeleport.sendMessage(ChatColor.DARK_GREEN + "You have been teleported.");
    }
}
